iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 23
0

來看範例

我們用幾個簡單的textView來顯示從api撈回來的資料,包括商品名、商品描述、價錢及數量,並藉由輸入editText來更改viewModel中資料的值,進而讓其他訂閱viewModel的textView來更新資料。

1.添加依賴 lifecycle_version目前為2.2.0

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

2.寫一個類別,模擬取得API資料的部分

interface IProductAPI {
    interface LoadAPICallBack {
        fun onGetResult(productResponse: ProductResponse)
    }

    fun getProduct(productId:String, loadAPICallBack: LoadAPICallBack)
}

class ProductAPI: IProductAPI {

    override fun getProduct(productId:String, loadAPICallBack: IProductAPI.LoadAPICallBack) {
        //模擬從API取得資料
        val handler = Handler()
        handler.postDelayed(Runnable {
            val productResponse = ProductResponse()
            productResponse.id = "pixel3"
            productResponse.name = "Google Pixel 3"
            productResponse.price = 27000
            loadAPICallBack.onGetResult(productResponse)
        }, 1000)
    }
}

2.寫Repository,來解析與處理資料。

interface IProductRepository {
    fun getProduct(productId: String, loadProductCallback: LoadProductCallback)

    fun buy(id: String, items: Int, callback: BuyProductCallback)

    interface LoadProductCallback {

        fun onProductResult(productResponse: ProductResponse)
    }

    interface BuyProductCallback {

        fun onBuyResult(isSuccess: Boolean)
    }

}

class ProductRepository(private val productAPI: IProductAPI) : IProductRepository {

    override fun buy(id: String, items: Int, callback: IProductRepository.BuyProductCallback) {
        //模擬購買成功
        callback.onBuyResult(true)
    }

    override fun getProduct(productId: String, loadProductCallback: IProductRepository.LoadProductCallback) {

        productAPI.getProduct(productId, object : IProductAPI.LoadAPICallBack {
            override fun onGetResult(productResponse: ProductResponse) {
                loadProductCallback.onProductResult(productResponse)

            }
        })
    }
}

3.此時就是MVVM和MVP最不同的地方,ViewModel並不使用callback的方式來通知View,而是用Observer pattern的概念,由View來訂閱(subscribe)ViewModel中它要的資料,並在資料異動時才更新UI,因此,MVVM都會搭配如Data Binding等library來實現Observer pattern。

class ProductViewModel(private val productRepository: IProductRepository) :ViewModel(){

    //將變數設為LiveData型態
    val productName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }
    val productPrice: MutableLiveData<Int> by lazy {
        MutableLiveData<Int>()
    }
    val productCount: MutableLiveData<Int> by lazy {
        MutableLiveData<Int>()
    }
    
    fun getProduct(productId: String) {
        productRepository.getProduct(productId, object : IProductRepository.LoadProductCallback {
            override fun onProductResult(productResponse: ProductResponse) {

                //用setValue來改變值
                productName.value = productResponse.name
                productDesc.value = productResponse.desc
                productPrice.value = productResponse.price
            }
        })
    }
    fun updateProduct(name:String,price:Int,count:Int){
        productName.value = name
        productPrice.value = price
        productCount.value = count
    }

}

4.在activity處理dataBinding與實例化repository還有viewModel

class ProductActivity : AppCompatActivity() {

    private val productId = "pixel3"

    private lateinit var model:ProductViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_product)

        val productAPI = ProductAPI()
        val productRepository = ProductRepository(productAPI)
        model = ProductViewModel(productRepository)
        model.getProduct(productId)

        val observerName = Observer<String>{ newName->
            tv_name.text = newName
        }
        val observerPrice = Observer<Int>{ newName->
            tv_price.text = newName.toString()
        }
        val observerCount = Observer<Int>{ newName->
            tv_counts.text = newName.toString()
        }

        //第一個參數為lifecycle的owner
        model.productName.observe(this,observerName)
        model.productPrice.observe(this,observerPrice)
        model.productCount.observe(this,observerCount)

        btn_update.setOnClickListener{
            model.updateProduct(
                et_name.text.toString(),
                et_price.text.toString().toInt(),
                et_count.text.toString().toInt())
        }
    }

}

5.layout,無特別的地方。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp">

    <TextView

        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="36sp" />

    <TextView
        android:id="@+id/tv_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:textSize="24sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="數量:"
            android:textSize="24sp" />

        <TextView
            android:id="@+id/tv_counts"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="start"
            android:layout_marginTop="12dp"
            android:textSize="24sp" />

    </LinearLayout>

    <EditText
        android:id="@+id/et_name"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:hint="品名" />

    <EditText
        android:id="@+id/et_price"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:hint="價格" />

    <EditText
        android:id="@+id/et_count"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:hint="數量" />

    <Button
        android:id="@+id/btn_update"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="24dp"
        android:padding="10dp"
        android:text="更新數值" />
</LinearLayout>

上一篇
MVVM架構與data binding [上]
下一篇
MVVM架構(二) [上]
系列文
Android Kotlin開發 -小嫩雞的30篇精選筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言